<?php
class TemplateParser extends Module{
	
	public $assets = null;
	public $includes = null;
	public $loops = null;
	public $html = null;
	public $vars = null;
	public $profiler = null;
	
	public function TemplateParser(&$application){
		$this->assets = array('Variable','Loop',INC_PATH.'3dparty/simple_html_dom.php');
		$this->Module($application);
		$this->profiler = new Profiler();
		$this->includes = array();
		$this->loops = array();
		$this->html = array();
		$this->vars = array();
	}
	
	public function parse($name, $file){
		$this->profiler->start();
		$dom = $this->load_from_file($file);
		$dom = $this->parse_includes($dom);
		$dom = $this->parse_loops($dom);
		$dom = $this->parse_vars($dom);
		$running_time = $this->profiler->end();
		$this->app->err->debug('Parse <strong>'.$name.'</strong> template ('.$running_time.')');
		return $dom->save();
	}
	
	public function parse_loop($name, $arr){
		$this->loops[$name] = $arr ? $arr : array();
	}
	
	public function parse_includes($dom){
		foreach($dom->find('include') as $inc){
			if(!in_array($inc->name, array_keys($this->includes))){
				if($inc->file){
					$file = APP_TPL_PATH.$inc->file;
					if(!file_exists($file)){
						$file = null;
						$this->app->err->dump_error('File <strong>'.$file.'</strong> does not exist (include <strong>'.$inc->name.'</strong>).');
					}
				}else{
					$this->app->err->dump_error('Include <strong>'.$inc->name.'</strong> has no file attribute.');
				}
			}else{
				$file = $this->includes[$inc->name];
			}
			if($inc->name && $file){
				$html = $this->parse($inc->name, $file);
				$inc->outertext = $html;
			}
		}
		return $dom;
	}
	
	public function parse_loops($dom){
		foreach($dom->find('loop') as $loop){
			if(in_array($loop->name, array_keys($this->loops))){
				$loop_values = $this->loops[$loop->name];
			}else{
				$loop_values = is_array($this->vars[$loop->name]) ? $this->vars[$loop->name] : array();
			}
			$loop_obj = new Loop($this, $loop->innertext, $loop_values);
			$loop->outertext = $loop_obj->evaluate();
		}
		return $dom;
	}
	
	public function parse_vars($dom){
		preg_match_all('`\{\$(.*)\}`',$dom->save(),$matches);
		if($matches[1]){
			foreach($matches[1] as $key => $var_logic){
				$text_position = strpos($dom->save(), $matches[0][$key]);
				$var = new Variable($var_logic, $this->vars);
				$eval = $var->evaluate();
				$new_dom = str_replace($matches[0][$key], $eval['replacement'], $dom->save());
				$dom = $this->load_from_string($new_dom);
				//tag & ptag
				if($eval['tag']){
					$this->delete_tag($dom, $eval['tag'], $text_position);
				}
				if($eval['ptag']){
					$this->delete_tag($dom, $eval['ptag'], $text_position, false);
				}
			}
		}
		return $dom;
	}
	
	public function delete_tag(&$dom, $tagbody, $limit_position, $delete_content=true){
		list($tag, $num) = explode(',',$tagbody);
		$tag = trim($tag);
		$num = trim($num)+0;
		$results = array();
		foreach($dom->find($tag) as $t){
			if(strpos($dom->save(), $t->outertext) < $limit_position) $results[] = $t;
		}
		$results = array_reverse($results);
		$results = array_slice($results, $num);
		$results[0]->outertext = ($delete_content ? '' : $results[0]->innertext);
	}
	
	public function gather_css($html){//gathers all inline css and puts it into the header
		$dom = new simple_html_dom;
		$dom->load($html, false);
		$head = $dom->find('head', 0);
		if($head){
			//find and remove inline style
			foreach($dom->find('[style]') as $obj){
				$style = $obj->style;
				if($style!=''){
					if(in_array($style, array_values($this->app->template_css_class))){//style already defined as class
						foreach($this->app->template_css_class as $class => $css){
							if($css==$style){
								break;
							}
						}
					}else{//style undefined
						$class = $this->app->template_css_class_i;
						$this->app->template_css_class[$class] = $style;
						$this->app->template_css_class_i++;
					}
				}
				if($obj->class){//class defined //append new one
					$obj->class.=' '.TPL_GATHER_CSS_PREFIX_CLASS.$class;
				}else{
					$obj->class = TPL_GATHER_CSS_PREFIX_CLASS.$class;
				}
				$obj->style = null;
			}
			//add new style to the header
			$style_arr = array();
			foreach($this->app->template_css_class as $key => $val){
				$style_arr[] = '.'.TPL_GATHER_CSS_PREFIX_CLASS.$key.'{'.$val.'}';
			}
			$style_html = implode("\n\t", $style_arr);
			$style_tag = $dom->find('head style',0);
			if($style_tag){
				$style_tag->innertext.= $style_html;
			}else{
				$head->innertext.= "\t".'<style type="text/css">'."\n\t".$style_html."\n\t".'</style>'."\n";
			}
		}
		return $dom->save();
	}
	
	public function load($name, $file){
		$this->includes[$name] = $file;
	}
	
	public function load_from_file($file){
		$dom = new simple_html_dom;
	    $args = func_get_args();
	    $dom->load(call_user_func_array('file_get_contents', $args), true);
	    return $dom;
	}
	
	public function load_from_string($str, $lowercase=true){
		$dom = new simple_html_dom;
	    $dom->load($str, $lowercase);
	    return $dom;
	}
}
?>